package com.dooioo.pns.api.utils;

import com.dooioo.pns.core.config.Constants;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.http.Header;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.ProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Created with IntelliJ IDEA.
 * PackageName:com.dooioo.pns.api.utils
 * Author: Jerry.hu
 * Create: Jerry.hu (2015-05-11 下午5:34)
 * Description:
 * To change this template use File | Settings | File Templates.
 */
public class HttpClientUtil {
	private static HttpClientUtil httpClientUtil;
	private CloseableHttpClient httpClient;

	private final Logger logger = Logger.getLogger(HttpClientUtil.class);
	public HttpClientUtil() {
		PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
		cm.setMaxTotal(200);
		cm.setDefaultMaxPerRoute(20);
		httpClient = HttpClients.custom().setConnectionManager(cm).setConnectionManagerShared(true).build();
	}

	public synchronized static HttpClientUtil getInstance() {
		if(httpClientUtil == null){
			httpClientUtil = new HttpClientUtil();
		}
		return httpClientUtil;
	}

	/**
	 * http get 请求
	 * @param url 请求的url
	 * @param params 请求的url 参数
	 * @return * @return 消息实体 String
	 * @throws IOException
	 * @throws ProtocolException
	 * @throws ConfigurationException
	 */
	public String doGetResult(String url,Map<String,String> params,Map<String,String>  headerMap) throws IOException,
			ProtocolException, ConfigurationException {
		List<NameValuePair> urlParams = getParamsList(params);
		logger.info("请求成功url=====>>>"+url);
		if (urlParams != null && urlParams.size() > 0) {
			String formatParams = URLEncodedUtils.format(urlParams, Constants.ENCODING);
			url = (url.indexOf("?")) < 0 ? (url + "?" + formatParams) : (url.substring(0, url.indexOf("?") + 1) + formatParams);
		}
		HttpGet httpGet = new HttpGet(url);
		if(headerMap != null && !headerMap.isEmpty()){
			httpGet.setHeaders(getHeaders(headerMap));
		}
		return execute(httpGet);
	}

	/**
	 * http post josn参数请求
	 * @param url 请求的url
	 * @param json 请求的json参数
	 * @param headerMap 请求的头部参数
	 * @return 消息实体 String
	 * @throws IOException
	 * @throws ProtocolException
	 * @throws ConfigurationException
	 */
	public String doPostJsonResult(String url,String json,Map<String,String>  headerMap) throws IOException,
			ProtocolException, ConfigurationException {
		logger.info("请求成功url=====>>>"+url);
		HttpPost post = new HttpPost(url);
		if(headerMap != null && !headerMap.isEmpty()){
			post.setHeaders(getHeaders(headerMap));
		}
		StringEntity se = new StringEntity(json, Constants.ENCODING);
		se.setContentType(Constants.CONTENT_TYPE_TEXT_JSON);
		se.setContentEncoding(new BasicHeader(HTTP.CONTENT_TYPE, Constants.CONTENT_TYPE));
		post.setEntity(se);
		return execute(post);
	}

	/**
	 * http put json 请求
	 * @param url 请求的url
	 * @param json josn 参数
	 * @param headerMap 头部参数
	 * @return 返回的消息实体 string
	 * @throws IOException
	 * @throws ProtocolException
	 * @throws ConfigurationException
	 */
	public String doPutJsonResult(String url,String json,Map<String,String>  headerMap) throws IOException,
			ProtocolException, ConfigurationException {
		logger.info("请求成功url=====>>>"+url);
		HttpPut put = new HttpPut(url);
		if(headerMap != null && !headerMap.isEmpty()){
			put.setHeaders(getHeaders(headerMap));
		}
		StringEntity se = new StringEntity(json, Constants.ENCODING);
		se.setContentType(Constants.CONTENT_TYPE_TEXT_JSON);
		se.setContentEncoding(new BasicHeader(HTTP.CONTENT_TYPE, Constants.CONTENT_TYPE));
		put.setEntity(se);
		return execute(put);
	}

	/**
	 * http post 表单请求
	 * @param url 请求的url
	 * @param params 表单参数
	 * @param headerMap 头部参数
	 * @return 消息实体 String
	 * @throws IOException
	 * @throws ProtocolException
	 * @throws ConfigurationException
	 */
	public String doPostResult(String url,Map<String,String> params,Map<String,String>  headerMap) throws IOException,
			ProtocolException, ConfigurationException {
		List<NameValuePair> urlParams = getParamsList(params);
		logger.info("请求成功url=====>>>"+url);
		HttpPost post = new HttpPost(url);
		if(headerMap != null && !headerMap.isEmpty()){
			post.setHeaders(getHeaders(headerMap));
		}
		post.setEntity(new UrlEncodedFormEntity(urlParams,Constants.ENCODING));
		return execute(post);
	}

	/**
	 * http put 表单请求
	 * @param url 请求的url
	 * @param params 表单参数
	 * @param headerMap 头部参数
	 * @return 消息实体 String
	 * @throws IOException
	 * @throws ProtocolException
	 * @throws ConfigurationException
	 */
	public String doPutResult(String url,Map<String,String> params,Map<String,String>  headerMap) throws IOException,
			ProtocolException, ConfigurationException {
		List<NameValuePair> urlParams = getParamsList(params);
		logger.info("请求成功url=====>>>"+url);
		HttpPut put = new HttpPut(url);
		if(headerMap != null && !headerMap.isEmpty()){
			put.setHeaders(getHeaders(headerMap));
		}
		put.setEntity(new UrlEncodedFormEntity(urlParams));
		return execute(put);
	}

	public String doDeleteJsonResult(String strUrl, Map<String, String> headerMap) throws IOException, ProtocolException, URISyntaxException {
		URL url = new URL(strUrl);
		URI uri = new URI(url.getProtocol(), url.getHost(), url.getPath(), url.getQuery(), null);
		logger.info("请求成功url=====>>>"+uri);
		HttpDelete delete = new HttpDelete(uri);
		if(headerMap != null && !headerMap.isEmpty()){
			delete.setHeaders(getHeaders(headerMap));
		}
		return execute(delete);
	}

	/**
	 * http 执行请求
	 * @param httpRequestBase 请求模式
	 * @return 消失实体 String
	 * @throws IOException
	 * @throws ProtocolException
	 */
	public String execute(HttpRequestBase httpRequestBase) throws IOException, ProtocolException {
		RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(5000).setConnectTimeout(5000).build();//设置请求和传输超时时间
		httpRequestBase.setConfig(requestConfig);
		try (CloseableHttpResponse response = httpClient.execute(httpRequestBase)) {
			if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK
					|| response.getStatusLine().getStatusCode() == HttpStatus.SC_CREATED) {
				String result = EntityUtils.toString(response.getEntity(), Constants.ENCODING);
				logger.info("请求成功=====>>>"+result);
				return result;
			}else{
				throw new ProtocolException("接口返回状态异常"+response+"\n====返回值为:>>>"+EntityUtils.toString(response.getEntity(), Constants.ENCODING));
			}
		} catch (IOException e) {
			throw new IOException("接口数据异常" + e);
		}
	}

	/**
	 * 获取url 参数信息
	 * @param paramsMap 参数map
	 * @return 返回url 参数集合
	 */
	private List<NameValuePair> getParamsList(Map<String,String> paramsMap){
		if(paramsMap == null || paramsMap.isEmpty()){
			return new ArrayList<>();
		}
		return paramsMap.entrySet().stream().map(entry -> new BasicNameValuePair(entry.getKey(), entry.getValue().trim())).collect(Collectors.toList());
	}

	/***
	 * 获取头部参数信息
	 * @param headerMap 头部参数map
	 * @return 头部参数信息数组
	 */
	private Header [] getHeaders(Map<String,String> headerMap){
		Header [] headers = new Header[headerMap.size()];
		int i = 0;
		for (Map.Entry<String,String> entry : headerMap.entrySet()){
			headers[i] = new BasicHeader(entry.getKey().trim(),entry.getValue().trim());
			i++;
		}
		return headers;
	}
}
